package library;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class Member {
    private final MemberId id;
    private final String name;
    private final List<Loan> loanHistory;
    private static final int MAX_LOANS = 3;

    public Member(MemberId id, String name) {
        this.id = Objects.requireNonNull(id, "Member id cannot be null");
        this.name = Objects.requireNonNull(name, "Name cannot be null");
        this.loanHistory = new ArrayList<>();
    }

    public Loan borrowBook(Book book, LocalDateTime borrowDate) {
        if (!canBorrow()) {
            throw new IllegalStateException("Member has reached maximum number of loans");
        }
        if (hasOverdueLoans()) {
            throw new IllegalStateException("Member has overdue loans");
        }
        if (!book.isAvailable()) {
            throw new IllegalStateException("Book is not available");
        }

        book.borrow();
        Loan loan = new Loan(new LoanId(id.getValue() + "-" + book.getId().getValue()),
                            book, this, borrowDate);
        loanHistory.add(loan);
        return loan;
    }

    public void returnBook(Loan loan, LocalDateTime returnDate) {
        if (!loanHistory.contains(loan)) {
            throw new IllegalStateException("Loan not found for this member");
        }
        if (loan.isReturned()) {
            throw new IllegalStateException("Book already returned");
        }

        loan.returnBook(returnDate);
        loan.getBook().returnBook();
    }

    public boolean canBorrow() {
        return getActiveLoans().size() < MAX_LOANS;
    }

    public boolean hasOverdueLoans() {
        return getActiveLoans().stream()
                .anyMatch(Loan::isOverdue);
    }

    private List<Loan> getActiveLoans() {
        return loanHistory.stream()
                .filter(loan -> !loan.isReturned())
                .toList();
    }

    public MemberId getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public List<Loan> getLoanHistory() {
        return new ArrayList<>(loanHistory);
    }
}

// Value Object
class MemberId {
    private final String value;

    public MemberId(String value) {
        this.value = Objects.requireNonNull(value, "MemberId value cannot be null");
    }

    public String getValue() {
        return value;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MemberId memberId = (MemberId) o;
        return Objects.equals(value, memberId.value);
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }
}
